// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module psu_ctrl
(
// ------------------------
// Clock and Reset signals
// ------------------------
	input       		iClk, 										//clock for sequential logic 
   input       		iRst_n, 										//reset signal from PLL Lock, resets state machine to initial state
// ----------------------------
// inputs and output regs
// ---------------------------- 	
	input					iPsu_enable,								//comming from master seq, triggerred by BMC_ONCTL_N
	input					iFM_S5_WITH_12V_N,						//Active low, indicate that 12V main power should be open even in S5 state
	input					iPWRGD_PS_PWROK,							//Signal generated by the PSU, indicates when 12V Main is stablished
	input					iPWRGD_P3V3,								//Power good coming from 3.3V voltage regulator (powered by 12V main)
	input					iClear_error_state,
	
	output reg			oFM_PS_EN,									//Enables PSU
	output reg			oFM_P5V_SW_EN,								//Enable P5V Main power switch
	output reg			oFM_P3V3_EN,								//Enable P3V3 Main VR
	output reg			oFM_AUX_SW_EN,								//Enable P12V_AUX Switch
	output reg			oFM_P12V_DIMM_PCIE_SW_CPU0_EN,		//Enable P12V MIAN power for CPU0 Memory and PCIe devices
	output reg			oFM_P12V_DIMM_PCIE_SW_CPU1_EN,		//Enable P12V MIAN power for CPU1 Memory and PCIe devices
	output reg			oFM_PLD_CLKS_DEV_EN,						//output reg to enable 100MHz external generator from CK440
	
	output            oPSU_FAULT,
	output            oP3V3_FAULT,
	
	output reg			oDone, 										//Indicates if the function is done
	output reg			oFault, 										//Failure output reg, to indicate to master sequencer that something failed on this block
	output reg	[2:0]	oFaultCode, 									//This output reg indicates to Master which is the code of the failure
    input                rjo_ready,
	input                rjo_ready_sec

);


//////////////////////////////////////////////////////////////////////////////////
// States for FSM
//////////////////////////////////////////////////////////////////////////////////
	localparam ST_INIT               = 4'd0;
	localparam ST_S5_12V             = 4'd1;
	localparam ST_ON	             	= 4'd2;
	localparam ST_P3V3_OK            = 4'd3;
	localparam ST_DONE               = 4'd4;
	localparam ST_PWR_OFF           	= 4'd5;
	localparam ST_PSU_FAULT          = 4'd6;
	localparam ST_P3V3_FAULT         = 4'd7;

//////////////////////////////////////////////////////////////////////////////////
// Parameters
//////////////////////////////////////////////////////////////////////////////////
	localparam  LOW =1'b0;
	localparam  HIGH=1'b1;

//////////////////////////////////////////////////////////////////////////////////
// Internal Signals
//////////////////////////////////////////////////////////////////////////////////
	reg	[3:0]	state;
	
	reg   rPWRGD_PS_PWROK_FF;
	reg   rPWRGD_P3V3_FF;
	reg   rPSU_FAULT_FF;
	reg   rP3V3_FAULT_FF;
	
//////////////////////////////////////////////////////////////////////////////////
// Combinational logic
//////////////////////////////////////////////////////////////////////////////////	

   assign 	oP3V3_FAULT   = rP3V3_FAULT_FF;
	assign   oPSU_FAULT    = rPSU_FAULT_FF;

	
//////////////////////////////////////////////////////////////////////////////////
// PSU FAULT AND P3V3 FAULT logic
//////////////////////////////////////////////////////////////////////////////////	
always @(posedge iClk or negedge iRst_n) begin
	if(!iRst_n) begin		
      rPWRGD_PS_PWROK_FF               <= LOW;
		rPWRGD_P3V3_FF                   <= LOW;
		rPSU_FAULT_FF                    <= LOW;
		rP3V3_FAULT_FF                   <= LOW;
   end
	else begin
		rPWRGD_PS_PWROK_FF               <= iPWRGD_PS_PWROK;
		rPWRGD_P3V3_FF                   <= iPWRGD_P3V3;
		rPSU_FAULT_FF                    <= ((iPsu_enable || !iFM_S5_WITH_12V_N) && (rPWRGD_PS_PWROK_FF && !iPWRGD_PS_PWROK))  ? HIGH : rPSU_FAULT_FF;     //PS_EN is on and PS_PWRGD is down
		rP3V3_FAULT_FF                   <= (iPsu_enable && rPWRGD_P3V3_FF && !iPWRGD_P3V3)                                    ? HIGH : rP3V3_FAULT_FF;    //iPsu_enable is on and PWRGD_P3V3 is down
		if (iClear_error_state) begin
			rPSU_FAULT_FF                <= LOW;
			rP3V3_FAULT_FF               <= LOW;
		end
	end
end
	
	
	
//////////////////////////////////////////////////////////////////////////////////
// PSU_check FSM logic
//////////////////////////////////////////////////////////////////////////////////	
always @(posedge iClk or negedge iRst_n) begin
	if(!iRst_n) begin													//reset state
		state 									<= ST_INIT;			//Initail state for state
		
		oFM_PS_EN 								<= LOW;				//Initail state of output
		oFM_P5V_SW_EN 							<= LOW;				//Initail state of output       
      oFM_P3V3_EN            				<= LOW;        	//Initail state of output
      oFM_AUX_SW_EN 							<= LOW;				//Initail state of output
		oFM_P12V_DIMM_PCIE_SW_CPU0_EN 	<=	LOW;				//Initail state of output
		oFM_P12V_DIMM_PCIE_SW_CPU1_EN		<=	LOW;				//Initail state of output
		oFM_PLD_CLKS_DEV_EN					<=	LOW;				//Initail state of output
		oDone										<=	LOW;				//Initail state of output
		oFault									<=	LOW;				//Initail state of output
		oFaultCode								<= 3'b000;			//Initail state of output
		
	end
	
	else begin
		case(state)
			ST_INIT: begin
			    if (rjo_ready && rjo_ready_sec) begin
				oFM_PS_EN 								<= LOW;				
				oFM_P5V_SW_EN 							<= LOW;				       
				oFM_P3V3_EN            				<= LOW;        	
				oFM_AUX_SW_EN 							<= LOW;				
				oFM_P12V_DIMM_PCIE_SW_CPU0_EN 	<=	LOW;				
				oFM_P12V_DIMM_PCIE_SW_CPU1_EN		<=	LOW;				
				oFM_PLD_CLKS_DEV_EN					<=	LOW;				
				oDone										<=	LOW;				
				oFault									<=	LOW;				
				oFaultCode								<= 3'b000;

				if(iPsu_enable || !iFM_S5_WITH_12V_N) begin		//if enable assert from master or in S5 WITH 12V MAIN mode (iFM_S5_WITH_12V_N is low)
					state	<= 	ST_ON;									//move to ST_ON
				end
				else begin
					state	<=		ST_INIT;									//keep in INIT 
				end
			end


			end	//end state of INIT			
			
			ST_ON: begin
				oFM_PS_EN 								<= HIGH;			//PSU ON		
				oFM_P5V_SW_EN 							<= LOW;				       
				oFM_P3V3_EN            				<= LOW;        	
				oFM_AUX_SW_EN 							<= LOW;				
				oFM_P12V_DIMM_PCIE_SW_CPU0_EN 	<=	LOW;				
				oFM_P12V_DIMM_PCIE_SW_CPU1_EN		<=	LOW;				
				oFM_PLD_CLKS_DEV_EN					<=	LOW;				
				oDone										<=	LOW;				
				oFault									<=	LOW;				
				oFaultCode								<= 3'b000;
				
				if(!iPsu_enable && iFM_S5_WITH_12V_N) begin		//if PSU not enabled and in normal mode
					state	<=		ST_INIT;
				end
				else if (!iFM_S5_WITH_12V_N && iPWRGD_PS_PWROK)	begin							//if in S5_WITH_12V mode
					state	<=		ST_S5_12V;								//move to ST_S5_12V
				end
				else if (iPsu_enable && iPWRGD_PS_PWROK && iFM_S5_WITH_12V_N)	begin		//if PS_PWROK back from PSU and in normal mode
					state	<=		ST_P3V3_OK;								//move to ST_P3V3_OK
				end
				else if (rPSU_FAULT_FF) begin	                  //if PSU pwr_Ok goes down, move to faultState
					state	<=		ST_PSU_FAULT;							//move to ST_PSU_FAULT	
				end
				else begin
					state	<=		ST_ON;									//keep in ST_ON
				end
				
			end	//end state of ST_ON			
			
			ST_S5_12V: begin
				oFM_PS_EN 								<= HIGH;			//PSU ON		
				oFM_P5V_SW_EN 							<= LOW;				       
				oFM_P3V3_EN            				<= LOW;        	
				oFM_AUX_SW_EN 							<= HIGH;			//Switch P12V to main power			
				oFM_P12V_DIMM_PCIE_SW_CPU0_EN 	<=	HIGH;			//Open CPU0 MEM and PCIe 12V power 	
				oFM_P12V_DIMM_PCIE_SW_CPU1_EN		<=	HIGH;			//Open CPU1 MEM and PCIe 12V power 	
				oFM_PLD_CLKS_DEV_EN					<=	LOW;				
				oDone										<=	LOW;				
				oFault									<=	LOW;				
				oFaultCode								<= 3'b000;
				
				if(!iPsu_enable && iFM_S5_WITH_12V_N) begin		//if PSU not enabled and in normal mode
					state	<=		ST_INIT;
				end
				else if (iPsu_enable && iPWRGD_PS_PWROK) begin	//in S5 WITH 12V mode, if PSU enabled and PS_PWROK back from PSU
					state	<=		ST_P3V3_OK;								
				end
				else if (rPSU_FAULT_FF)	begin	                  //if PSU pwr_Ok goes down, move to faultState
					state	<=		ST_PSU_FAULT;							//move to ST_PSU_FAULT				
				end
				else begin
					state <= ST_S5_12V;									//keep in ST_S5_12V
				end
				
			end	//end stae of ST_S5_12V
			
			ST_P3V3_OK: begin
				oFM_PS_EN 								<= HIGH;			//PSU ON		
				oFM_P5V_SW_EN 							<= HIGH;			//Open P5V main power switch	       
				oFM_P3V3_EN            				<= HIGH;       //Open P3V3 main VR	 	
				oFM_AUX_SW_EN 							<= HIGH;			//Switch P12V to main power			
				oFM_P12V_DIMM_PCIE_SW_CPU0_EN 	<=	HIGH;			//Open CPU0 MEM and PCIe 12V power 	
				oFM_P12V_DIMM_PCIE_SW_CPU1_EN		<=	HIGH;			//Open CPU1 MEM and PCIe 12V power 	
				oFM_PLD_CLKS_DEV_EN					<=	LOW;
				oDone										<=	LOW;				
				oFault									<=	LOW;				
				oFaultCode								<= 3'b000;
				
				if(iPsu_enable && iPWRGD_P3V3) begin				//if PSU enable and P3V3 Main power good move to st_done
					state	<= ST_DONE;
				end
				else if (rP3V3_FAULT_FF) begin		            //if P3V3 power not good
					state	<=	ST_P3V3_FAULT;								//move to ST_P3V3_FAULT
				end
				else if (!iPsu_enable && !iFM_S5_WITH_12V_N) begin		//if PSU not enabled and in S5 WITH 12V mode
					state <=	ST_S5_12V;									//back to ST_S5_12V
				end
				else if (!iPsu_enable && iFM_S5_WITH_12V_N)	begin		//if PSU not enabled and in normal mode
					state	<=	ST_INIT;										//back to ST_INIT;
				end
				else begin
					state	<= ST_P3V3_OK;									//keep in ST_P3V3_OK
				end
				
			end	//end state of ST_P3V3_OK
			
			ST_DONE: begin
				oFM_PS_EN 								<= HIGH;			//PSU ON
				oFM_P5V_SW_EN 							<= HIGH;			//Open P5V main power switch	       
				oFM_P3V3_EN            				<= HIGH;       //Open P3V3 main VR	 	
				oFM_AUX_SW_EN 							<= HIGH;			//Switch P12V to main power			
				oFM_P12V_DIMM_PCIE_SW_CPU0_EN 	<=	HIGH;			//Open CPU0 MEM and PCIe 12V power 	
				oFM_P12V_DIMM_PCIE_SW_CPU1_EN		<=	HIGH;			//Open CPU1 MEM and PCIe 12V power 	
				oFM_PLD_CLKS_DEV_EN					<=	HIGH;			//Open CK440 clock	
				oDone										<=	HIGH;			//PSU seq done	
				oFault									<=	LOW;				
				oFaultCode								<= 3'b000;
				
				if(rPSU_FAULT_FF) begin			                  //if PSU pwr_Ok goes down, move to faultState
					state	<=		ST_PSU_FAULT;
				end
				else if(rP3V3_FAULT_FF) begin		               //if 3.3 V pwrgd goes down, move to faultState
					state	<=		ST_P3V3_FAULT;
				end
				else if(!iPsu_enable && iPWRGD_P3V3 && iPWRGD_PS_PWROK) begin		//if enable is 0, move to ST_P3V3_OK (power done seq)
					state	<=		ST_PWR_OFF;
				end
				else begin
					state	<=		ST_DONE;									//keep in ST_DONE
				end
			end	//end state of ST_DONE
			
			ST_PWR_OFF: begin
				oFM_PS_EN 								<= HIGH;			//PSU still ON	
				oFM_P5V_SW_EN 							<= LOW;			//Turn off P5V main power switch	       
				oFM_P3V3_EN 							<= LOW;			//Turn off P5V main power switch	       
				oFM_AUX_SW_EN 							<= HIGH;			//Switch P12V to main power			
				oFM_P12V_DIMM_PCIE_SW_CPU0_EN 	<=	HIGH;			//Open CPU0 MEM and PCIe 12V power 	
				oFM_P12V_DIMM_PCIE_SW_CPU1_EN		<=	HIGH;			//Open CPU1 MEM and PCIe 12V power 	
				oFM_PLD_CLKS_DEV_EN					<=	LOW;			//Turn off CK440 clock	
				oFault									<=	LOW;				
				oFaultCode								<= 3'b000;
				
				if (!iPsu_enable && !iPWRGD_P3V3 || iClear_error_state) begin			//power down seq
					state	<=	ST_INIT;	
				end
				else begin
					state	<= ST_PWR_OFF;
				end
			end	//end state of ST_PWR_OFF
			
			ST_PSU_FAULT: begin
				oFM_PS_EN 								<= LOW;			//PSU off		
				oFM_P5V_SW_EN 							<= LOW;			//Turn off P5V main power switch	       
				oFM_P3V3_EN            				<= LOW;       	//Turn off P3V3 main VR	 	
				oFM_AUX_SW_EN 							<= LOW;			//Switch P12V to main power			
				oFM_P12V_DIMM_PCIE_SW_CPU0_EN 	<=	LOW;			//Open CPU0 MEM and PCIe 12V power 	
				oFM_P12V_DIMM_PCIE_SW_CPU1_EN		<=	LOW;			//Open CPU1 MEM and PCIe 12V power 	
				oFM_PLD_CLKS_DEV_EN					<=	LOW;			//Turn off CK440 clock	
				oDone										<=	LOW;			//PSU seq not done	
				oFault									<=	HIGH;			//Fault detect	
				oFaultCode								<= 3'b001;		//Fault code
				
				if (iClear_error_state) begin
					state                           <= ST_INIT;         //Initail state for state
					oFault                          <= LOW;             //Initail state of output
					oFaultCode                      <= 3'b000;          //Initail state of output
				end else begin
					state                           <= ST_PSU_FAULT;	//Infinite loop, keeping in faultSt
				end
			end	//end state of ST_PSU_FAULT
			
			ST_P3V3_FAULT: begin
				oFM_PS_EN 								<= LOW;			//PSU off		
				oFM_P5V_SW_EN 							<= LOW;			//Turn off P5V main power switch	       
				oFM_P3V3_EN            				<= LOW;       	//Turn off P3V3 main VR	 	
				oFM_AUX_SW_EN 							<= LOW;			//Switch P12V to main power			
				oFM_P12V_DIMM_PCIE_SW_CPU0_EN 	<=	LOW;			//Open CPU0 MEM and PCIe 12V power 	
				oFM_P12V_DIMM_PCIE_SW_CPU1_EN		<=	LOW;			//Open CPU1 MEM and PCIe 12V power 	
				oFM_PLD_CLKS_DEV_EN					<=	LOW;			//Turn off CK440 clock	
				oDone										<=	LOW;			//PSU seq not done	
				oFault									<=	HIGH;			//Fault detect	
				oFaultCode								<= 3'b010;		//Fault code
				
				if (iClear_error_state) begin
					state                           <= ST_INIT;         //Initail state for state
					oFault                          <= LOW;             //Initail state of output
					oFaultCode                      <= 3'b000;          //Initail state of output
				end else begin
					state                           <= ST_P3V3_FAULT;	//Infinite loop, keeping in faultSt
				end
			end	//end state of ST_P3V3_FAULT
			
			default: begin
			   oFM_PS_EN 								<= LOW;				
				oFM_P5V_SW_EN 							<= LOW;				       
				oFM_P3V3_EN            				<= LOW;        	
				oFM_AUX_SW_EN 							<= LOW;				
				oFM_P12V_DIMM_PCIE_SW_CPU0_EN 	<=	LOW;				
				oFM_P12V_DIMM_PCIE_SW_CPU1_EN		<=	LOW;				
				oFM_PLD_CLKS_DEV_EN					<=	LOW;				
				oDone										<=	LOW;				
				oFault									<=	LOW;				
				oFaultCode								<= 3'b000;
				
				state	<=	ST_INIT;
			end   //end state of default
			
		endcase
	end
end

endmodule
